package com.xiyuan.smartutils.xml;

import com.xiyuan.smartutils.Systems;
import com.xiyuan.smartutils.Validates;
import com.xiyuan.smartutils.annotation.AnAlias;
import com.xiyuan.smartutils.constants.AsciiConstants;
import com.xiyuan.smartutils.xml.annotation.XmlClassTag;
import com.xiyuan.smartutils.xml.annotation.XmlFieldNoGroup;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;


/**
 * Xms相关工具类
 *
 * @version v1.1.2 @author lgz 2017-8-21 新建与整理
 */
@AnAlias("Xmls")
public class Xmls extends Xmlx implements AsciiConstants
{
    
    /********************************************************/
    //提供静态的toString和toObject方法,取标准XML参数
    /********************************************************/
    
    /**
     * 默认的对象转XML字符串方法，不同的参数请单独使用Xml类
     * 
     * @param obj   对象
     * @return      返回XML字符串
     */
    public static String toString(Object obj)
    {
        return Xml.xml.toString(obj);
    }
    
    /**
     * 默认的XML字符串转换成对象，不同的参数请单独使用Xml类
     * 
     * @param str   XML字符串
     * @param clazz 转换成对象的类
     * @return      对应的对象
     */
    public static <T> T toObject(String str, Class<T> clazz)
    {
        return Xml.xml.toObject(str, clazz);
    }
    
    /********************************************************/
    //以下XML注解相关
    /********************************************************/
    
    /**
     * 获取类的XML标志，优先查@XmlTag，没有取@Alias，再没有取没有包结构的短类名
     * 
     * @param clazz 类结构
     * @return      XML标记，没有取短类名
     */
    public static String getXmlClassTag(Class<?> clazz)
    {
        if (clazz == null)
            return null;
        
        XmlClassTag xmlTag = clazz.getAnnotation(XmlClassTag.class);
        if (xmlTag != null && !Validates.isBlank(xmlTag.value()))
            return xmlTag.value().trim();
        
        AnAlias alias = clazz.getAnnotation(AnAlias.class);
        if (alias != null && !Validates.isBlank(alias.value()[0]))
            return alias.value()[0].trim();
        
        return clazz.getSimpleName();
    }
    
    /**
     * 判断XMLList是否需要组号
     * 
     * @param field 字段
     * @return      如果实现XmlFieldNoGroup则不需要，默认需要
     */
    public static boolean hasXmlFieldGroup(Field field)
    {
        return !field.isAnnotationPresent(XmlFieldNoGroup.class);
    }
    
    /********************************************************/
    //以下解析XML时需要的字符串分析方法
    /********************************************************/
    
    /**
     * 获取XML中属性列表
     * 
     * @param xml   XML字符串
     * @param name  字段名称
     * @return      XML子段列表
     */
    public static List<String> getXmlFieldList(String xml, String name)
    {
        List<String> list = new ArrayList<String>();
        
        String lField = "<"+name+">";
        String rField = "</"+name+">";
        int rLen = rField.length();
        
        for(int iLeft=xml.indexOf(lField);iLeft!=-1;iLeft=xml.indexOf(lField))
        {
            int iRight = xml.indexOf(rField, iLeft);
            if (iRight == -1)
                break;
            
            list.add(xml.substring(iLeft, iRight+rLen));
            xml = xml.substring(iRight+rLen);
        }
        
        return list;
    }
    
    /**
     * 读取XML中字段的值，允许没有field时返回空字符串
     * 
     * @param xml XML字符串
     * @param field 字段名
     * @return 返回XML中字段中的值
     * @throws Exception 如果字段内容不符合要求,则抛出此异常
     */
    public static String getXmlField(String xml, String field)
    {
        if (xml.length() < field.length() * 2 + 5)
            return null;
        
        String lField = "<"+field+">";
        String rField = "</"+field+">";
        int iLeft = xml.indexOf(lField);
        int iRight = xml.indexOf(rField);
        if (iLeft == -1 && iRight == -1)
            return null;
        
        if ((iLeft == -1 && iRight != -1) || (iLeft != -1 && iRight == -1))
            return null;
        
        int valueLen = iRight - iLeft - lField.length();
        if (valueLen <= 0)
            return null;
        
        return xml.substring(iLeft + lField.length(), iRight);
    }
    
    /**
     * 检查XML是否包含在tag内，并截除tag，返回截除后的XML
     * 
     * @param xml XML字符串
     * @param tag 标记
     * @return 返回被截除后的XML
     * @throws Exception 如果XML不是tag开头和结尾,则抛出此异常
     */
    public static String chkXmlByTag(String xml, String tag) throws Exception
    {
        if (xml.length() < tag.length() * 2 + 5)
        {
            throw new Exception("xml tag #"+tag+"# format error");
        }
        
        String lField = "<"+tag+">";
        String rField = "</"+tag+">";
        String left = xml.substring(0, lField.length());
        String right = xml.substring(xml.length() - rField.length());
        if (!lField.equals(left) || !rField.equals(right))
        {
            throw new Exception("xml tag #"+tag+"# format error");
        }
        else
        {
            xml = xml.substring(lField.length());
            xml = xml.substring(0, xml.length() - rField.length());
            return xml;
        }
    }
    
    /**
     * 检查XML中字段field的值，并截除field放置到buf中，返回截除后的XML
     * 
     * @param xml XML字符串
     * @param field 字段名
     * @param value 把被截取的值放置到buf中
     * @param len 值允许的最大长度
     * @param isFixed 值长度是否定长
     * @return 返回被截除后的XML
     * @throws Exception 如果字段内容不符合要求,则抛出此异常
     */
    public static String chkXmlByField(String xml, String field, StringBuffer value, int len, boolean isFixed) throws Exception
    {
        if (xml.length() < field.length() * 2 + 5)
        {
            throw new Exception("xml tag #"+field+"# format error");
        }
        
        String lField = "<"+field+">";
        String rField = "</"+field+">";
        int iLeft = xml.indexOf(lField);
        int iRight = xml.indexOf(rField);
        if (iLeft == -1 || iRight == -1)
        {
            throw new Exception("xml tag #"+field+"# format error");
        }
        
        int valueLen = iRight - iLeft - lField.length();
        if ((isFixed && valueLen != len) ||//F 且不等
            (!isFixed && (valueLen > len || valueLen < 1)))//V 且 (大于len 或 < 1)
        {
            throw new Exception("xml tag #"+field+"# format error");
        }
        
        value.append(xml.substring(iLeft + lField.length(), iRight));
        return xml.substring(iRight + rField.length());
    }
    

    /**
     * 检查XML中字段field的值，并截除field放置到buf中，返回截除后的XML,允许该字段为空
     * 
     * @param xml XML字符串
     * @param field 字段名
     * @param value 把被截取的值放置到buf中
     * @param len 值允许的最大长度
     * @param isFixed 值长度是否定长
     * @return 返回被截除后的XML
     * @throws Exception 如果字段内容不符合要求,则抛出此异常
     */
    public static String chkXmlByFieldAllowEmpty(String xml, String field, StringBuffer value, int len, boolean isFixed) throws Exception
    {
        String lField = "<"+field+">";
        String rField = "</"+field+">";
        int iLeft = xml.indexOf(lField);
        int iRight = xml.indexOf(rField);
        if (iLeft == -1 && iRight == -1)
            return xml;
        
        if ((iLeft == -1 && iRight != -1) || (iLeft != -1 && iRight == -1))
            throw new Exception("xml tag #"+field+"# format error");
        
        int valueLen = iRight - iLeft - lField.length();
        if (valueLen == 0)//为空则不判断isFixed,len
            return xml.substring(iRight + rField.length());
        
        if ((isFixed && valueLen != len) ||//F 且不等
            (!isFixed && (valueLen > len || valueLen < 1)))//V 且 (大于len 或 < 1)
        {
            throw new Exception("xml tag #"+field+"# format error");
        }
        
        value.append(xml.substring(iLeft + lField.length(), iRight));
        return xml.substring(iRight + rField.length());
    }
    
    /**
     * 检查XML中字段field的int值，并截除field值放置到buf中，返回截除后的XML
     * 
     * @param xml XML字符串
     * @param field 字段名
     * @param value 把被截取的值放置到buf中
     * @return 返回被截除后的XML
     * @throws Exception 如果字段不是int或格式不正确,则抛出此异常
     */
    public static String chkXmlByIntField(String xml, String field, StringBuffer value) throws Exception
    {
        if (xml.length() < field.length() * 2 + 5)
        {
            throw new Exception("xml tag #"+field+"# format error");
        }

        String lField = "<"+field+">";
        String rField = "</"+field+">";
        int iLeft = xml.indexOf(lField);
        int iRight = xml.indexOf(rField);
        if (iLeft == -1 || iRight == -1)
        {
            throw new Exception("xml tag #"+field+"# format error");
        }
        
        int valueLen = iRight - iLeft - lField.length();
        if (valueLen < 1)//nubmer不允许为空
        {
            throw new Exception("xml tag #"+field+"# format error");
        }
        
        String valueInt = xml.substring(iLeft + lField.length(), iRight);
        if (!Validates.isInteger(valueInt))
        {
            throw new Exception("xml tag #"+field+"# format error");
        }
        
        value.append(valueInt);
        return xml.substring(iRight + rField.length());
    }
    
    /**
     * 读取XML中字段的
     * 
     * @param xml XML字符串
     * @param field 字段名
     * @param len 值允许的最大长度
     * @param isFixed 值长度是否定长
     * @return 返回XML中字段中的值
     * @throws Exception 如果字段内容不符合要求,则抛出此异常
     */
    public static String getXmlField(String xml, String field, int len, boolean isFixed) throws Exception
    {
        if (xml.length() < field.length() * 2 + 5)
        {
            throw new Exception("xml tag #"+field+"# format error");
        }
        
        String lField = "<"+field+">";
        String rField = "</"+field+">";
        int iLeft = xml.indexOf(lField);
        int iRight = xml.indexOf(rField);
        if (iLeft == -1 || iRight == -1)
        {
            throw new Exception("xml tag #"+field+"# format error");
        }
        
        int valueLen = iRight - iLeft - lField.length();
        if ((isFixed && valueLen != len) ||//F 且不等
            (!isFixed && (valueLen > len || valueLen < 1)))//V 且 (大于len 或 < 1)
        {
            throw new Exception("xml tag #"+field+"# format error");
        }
        
        return xml.substring(iLeft + lField.length(), iRight);
    }
    
    /**
     * 读取XML中字段的int值 
     * 
     * @param xml XML字符串
     * @param field 字段名
     * @return int 返回XML中字段中的int值
     * @throws Exception 如果字段不是int或格式不正确,则抛出此异常
     */
    public static int getXmlInt(String xml, String field) throws Exception
    {
        if (xml.length() < field.length() * 2 + 5)
        {
            throw new Exception("xml tag #"+field+"# format error");
        }

        String lField = "<"+field+">";
        String rField = "</"+field+">";
        int iLeft = xml.indexOf(lField);
        int iRight = xml.indexOf(rField);
        if (iLeft == -1 || iRight == -1)
        {
            throw new Exception("xml tag #"+field+"# format error");
        }
        
        int valueLen = iRight - iLeft;
        if (valueLen < 1)//nubmer不允许为空
        {
            throw new Exception("xml tag #"+field+"# format error");
        }
        
        String valueInt = xml.substring(iLeft + lField.length(), iRight);
        if (!Validates.isInteger(valueInt))
        {
            throw new Exception("xml tag #"+field+"# format error");
        }
        
        return Integer.parseInt(valueInt);
    }
    
    /********************************************************/
    //以下解析XML属性方法
    /********************************************************/
    
    /**
     * 获取XML中属性字段
     * 
     * @param xml 指定的XML
     * @param name 指定的名称
     * @return 值
     * @throws Exception
     */
    public static String getString(String xml, String name) throws Exception
    {
        String lField = name + "=\"";
        String rField = "\"";
        int iLeft = xml.indexOf(lField);
        if (iLeft == -1)
            return null;
        
        int iRight = xml.indexOf(rField, iLeft+lField.length());
        if (iRight == -1)
            return null;
        
        return xml.substring(iLeft+lField.length(), iRight);
    }
    
    /**
     * 获取XML中属性字段
     * 
     * @param xml 指定的XML
     * @param name 指定的名称
     * @return 值
     * @throws Exception
     */
    public static int getInt(String xml, String name) throws Exception
    {
        String value = getString(xml, name);
        if (value == null)
            throw new Exception("未找到字段值");
        
        return Integer.parseInt(value);
    }
    
    /**
     * 获取XML中属性字段
     * 
     * @param xml 指定的XML
     * @param name 指定的名称
     * @return 值
     * @throws Exception
     */
    public static long getLong(String xml, String name) throws Exception
    {
        String value = getString(xml, name);
        if (value == null)
            throw new Exception("未找到字段值");
        
        return Long.parseLong(value);
    }
    

    /**
     * 获取XML中属性列表
     * 
     * @param xml   XML字符串
     * @param name  字段名称
     * @return      XML子段列表
     */
    public static List<String> getList(String xml, String name)
    {
        List<String> list = new ArrayList<String>();
        
        String lField = "<"+name+" ";
        String rField = "</"+name+">";
        String rField2 = "/>";
        
        for(int iLeft=xml.indexOf(lField);iLeft!=-1;iLeft=xml.indexOf(lField))
        {
            int len = rField.length();
            int iRight = xml.indexOf(rField, iLeft);
            if (iRight == -1)
            {
                iRight = xml.indexOf(rField2, iLeft);
                len = rField2.length();
            }
            
            if (iRight == -1)
                break;
            
            String str = xml.substring(iLeft, iRight+len);
            list.add(str);
            xml = xml.substring(iRight+len);
        }
        
        return list;
    }
}
